先拿book開刀,先改一個新的版本,原需要Book沒有作者欄位,添加上此欄位,並設定為必填項目,在command裡是必填,但aggregate及event為了保持相容性,還是會被迫使用Option選填的方式。
這邊只秀新增的欄位,既有的欄位都不變。
pub struct Book {
pub author: Option<String>,
}
impl Default for Book {
fn default() -> Self {
Self {
author: None,
}
}
}
pub enum BookCommand {
CreateBook {
author: String,
},
}
pub enum BookEvent {
BookCreated {
author: Option<String>,
}
}
更新事件版本,不同版號在未來upcaster裡要個別進行升版實作。
impl DomainEvent for BookEvent {
fn event_type(&self) -> String {
"BookEvent".to_string()
}
fn event_version(&self) -> String {
"0.2.0".to_string() // 這裡把原本的 0.1.0 改為 0.2.0
}
}
連動一起更新事件及指令的處理:
impl Aggregate for Book {
async fn handle( /* ... */) {
match command {
BookCommand::CreateBook {
author,
} => {
let event = BookEvent::BookCreated {
author: Some(author), // 事件欄位為了相同為Option
};
}
}
}
async fn apply( /* ... */) {
match event {
BookEvent::BookCreated {
author, // event 已是 Option
} => {
self.author = author; // aggregate 也是 Option
}
}
}
}
#[async_trait]
impl Query<Book> for BookQuery {
async fn dispatch(&self, aggregate_id: &str, events: &[EventEnvelope<Book>]) {
for event in events {
match &event.payload {
BookEvent::BookCreated { // Event裡新增欄位配合增加
author,
} => {
let book_dto = BookDto { /* ... */ } // 如有需要這裡的DTO再配合修改
}
}
}
}
}